package com.swotxu.oldwebproject.redis.connection.impl;

import com.swotxu.oldwebproject.redis.RedisManager;
import com.swotxu.oldwebproject.redis.connection.IRedisConnection;
import com.swotxu.oldwebproject.redis.utils.RedisSerializer;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Date: 2021/3/24 0024 13:45
 * @Author: swotxu
 */
public class RedisConnection implements IRedisConnection {
    private static final Logger logger = LoggerFactory.getLogger(RedisConnection.class);

    private RedisConnection(){}

    /**
     * 获取单例连接对象
     *
     * @return
     */
    public static IRedisConnection getInstance() {
        return IRedisConnectionHolder.INSTANCE;
    }
    static class IRedisConnectionHolder {
        private static IRedisConnection INSTANCE = new RedisConnection();
    }

    /**
     * 内部回调类
     * @param <T>
     */
    interface RedisCallback<T> {
        T call(Jedis jedis, Object params);
    }

    protected <T>T execute(RedisCallback<T> callback, Object... field) {
        JedisPool jedisPool = RedisManager.getJedisPool();
        Assert.notNull(jedisPool, "Redis连接异常，请检查服务!");
        Jedis jedis = null;
        try {
            // RedisManager.getRedisInstance() 可能获取不到 jeids 连接
            if((jedis = jedisPool.getResource()) != null){
                return callback.call(jedis, field);
            }
        } catch (JedisConnectionException e) {
            logger.error("redis连接异常，请检查redis服务器！", e);
            returnJedis(jedis);
        } catch (JedisDataException e) {
            logger.warn("redis操作失败！", e);
            returnBrokenJedis(jedis);
            jedis = null;
        } catch (Exception e) {
            logger.error("redis操作失败！", e);
        } finally {
            returnJedis(jedis);
        }
        logger.info("jedis is null or execute failed!");
        return null;
    }

    public static void returnJedis(final Jedis jedis) {
        if (jedis != null) {
            try {
                RedisManager.getJedisPool().returnResource(jedis);
            } catch (Exception e) {
                logger.error("Can not return redis instance -> " + e.getMessage());
            }
        }
    }

    public static void returnBrokenJedis(final Jedis jedis) {
        if (jedis != null) {
            try {
                RedisManager.getJedisPool().returnBrokenResource(jedis);
            } catch (Exception e) {
                logger.error("Can not return broken redis instance -> " + e.getMessage());
            }
        }
    }

    @Override
    public void close() {}

    @Override
    public Boolean isConnected() {
        return execute((jedis, params) -> jedis.isConnected());
    }

    @Override
    public Long hset(String key, String field, Object object) {
        if (key == null || field == null || object == null) {
            return null;
        }
        return execute((jedis, params) -> jedis.hset(key.getBytes(), field.getBytes(), RedisSerializer.serialize(object)));
    }

    @Override
    public String set(String key, Object object) {
        if (key == null || object == null) {
            return null;
        }
        return execute((jedis, params) -> jedis.set(key.getBytes(), RedisSerializer.serialize(object)));
    }

    @Override
    public Object hget(String key, String field) {
        if (key == null || field == null) {
            return null;
        }
        return execute((jedis, params) -> {
            byte[] bytes = jedis.hget(key.getBytes(), field.getBytes());
            Object result = null;
            if (bytes != null) {
                result = RedisSerializer.deserialize(bytes);
            }
            return result;
        });
    }

    @Override
    public List hmget(String key, String... field) {
        if (key == null || ArrayUtils.isEmpty(field)) {
            return null;
        }
        return execute((jedis, params) -> RedisSerializer.deserialize(jedis.hmget(key.getBytes(), RedisSerializer.toBinary(field))));
    }

    @Override
    public String hmset(String key, Map<String, Object> map) {
        if (key == null || CollectionUtils.isEmpty(map)) {
            return null;
        }
        return execute((jedis, params) -> jedis.hmset(key.getBytes(), RedisSerializer.toBinary(map)));
    }

    @Override
    public Object get(String key) {
        Assert.notNull(key, "key 不能为空");
        return execute((jedis, params) -> {
            byte[] bytes = jedis.get(key.getBytes());
            Object result = null;
            if (bytes != null) {
                result = RedisSerializer.deserialize(bytes);
            }
            return result;
        });
    }

    @Override
    public Long del(String... keys) {
        if (ArrayUtils.isEmpty(keys)) {
            return null;
        }
        return execute((jedis, params) -> jedis.del(keys));
    }

    @Override
    public Long hdel(String key, String... fields) {
        if (key == null || ArrayUtils.isEmpty(fields)) {
            return null;
        }
        return execute((jedis, params) -> jedis.hdel(key, fields));
    }

    @Override
    public Long expire(String key, int seconds) {
        if (key == null || seconds < 0) {
            return null;
        }
        return execute((jedis, params) -> jedis.expire(key, seconds));
    }

    @Override
    public Set<String> hkeys(String key) {
        Assert.notNull(key, "key 不能为空");
        return execute((jedis, params) -> jedis.hkeys(key));
    }

    @Override
    public Set<String> keys(String key) {
        Assert.notNull(key, "key 不能为空");
        return execute((jedis, params) -> jedis.keys(key));
    }

    @Override
    public Boolean exists(String key) {
        Assert.notNull(key, "key 不能为空");
        return execute((jedis, params) -> jedis.exists(key.getBytes()));
    }

    @Override
    public Boolean hexists(String key, String field) {
        Assert.notNull(key, "key 不能为空");
        Assert.notNull(field, "field 不能为空");
        return execute((jedis, params) -> jedis.hexists(key.getBytes(), field.getBytes()));
    }

    @Override
    public Object getSet(String key, Object value) {
        if (key == null || value == null) {
            return null;
        }
        return execute((jedis, params) -> {
            byte[] bytes = jedis.getSet(key.getBytes(), RedisSerializer.serialize(value));
            Object result = null;
            if (bytes != null) {
                result = RedisSerializer.deserialize(bytes);
            }
            return result;
        });
    }

}
